﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SC2BuildOrderQuickie
{

    public class App
    {
        public List<BOCode> AllBuilds { get; set; }
        public readonly PartitionList PartitionList = new PartitionList();

    }

    public class BuildOrderPartition
    {
        public readonly String Key;
        public List<BOCode> Builds = new List<BOCode>();
        private readonly int m_Bucket;
        public BuildOrderPartition( int bucket, String key) { { Key = key;
            m_Bucket = bucket;
        } }
        public void Add(BOCode bo) {
            Builds.Add(bo);
            Builds.Sort(delegate( BOCode lhs, BOCode rhs ) {
                            return lhs.SecondBuckets[ m_Bucket ] - rhs.SecondBuckets[ m_Bucket ];
                        });
        }

        public bool Equals(BuildOrderPartition other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return Equals(other.Key, Key);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != typeof(BuildOrderPartition)) return false;
            return Equals((BuildOrderPartition)obj);
        }

        public override int GetHashCode()
        {
            return (Key != null ? Key.GetHashCode() : 0);
        }
    }
    public class PartitionList
    {
        private List<Dictionary<String, BuildOrderPartition>> m_Partitions;
        public PartitionList()
        {
            m_Partitions = new List<Dictionary<string, BuildOrderPartition>>();
        }
        public BuildOrderPartition Get( int chunk, String key ) {
            BuildOrderPartition partition;
            if (m_Partitions[chunk].TryGetValue(key, out partition)) return partition;
            return null;
            
        }
        public void Include(BOCode bo)
        {
            for (int i = 0; i < bo.Length; i++)
            {
                Dictionary<String, BuildOrderPartition> hash;
                if (i >= m_Partitions.Count)
                {
                    hash = new Dictionary<string, BuildOrderPartition>();
                    m_Partitions.Add(hash);
                }
                else
                {
                    hash = m_Partitions[i];
                }

                BuildOrderPartition partition;
                String key = bo.GetSubset(i + 1);
                if (hash.TryGetValue(key, out partition) == false)
                {
                    partition = new BuildOrderPartition(i,key);
                    hash.Add(key, partition);
                }
                partition.Add(bo);
            }
        }
    }
    public class BOCode {
        private readonly String[] m_BuildBuckets;
        private readonly int[] m_SecondBuckets;
        private readonly int[] m_SupplyBuckets;
        private readonly String m_Player;
        private readonly String m_GameName;
        private readonly int m_Length;
        public int Length { get { return m_Length; } }

// example:
//0:Rubgish:ppppppppppp 15 96 ppNFpppNppGCppppppCpp 30 302 ppppppppppppppp 45 401 ppTG&4ppGppGGGGG~pp11kkkk 61 562 

        public String GetFileName() { return String.Format( "BO.{0}.{1}.txt", m_GameName, m_Player ); }

        public override string ToString() { return String.Format( "{0}.{1}", m_Player, m_GameName );}

        public BOCode(string build_order_formatted)
        {
            String[] blocks = build_order_formatted.Split(new[]{':'}, 3);
            m_GameName = blocks[ 0 ];
            m_Player = blocks[ 1 ];

            String[] build_order_chunks = blocks[ 2 ].Split( new[]{' '}, StringSplitOptions.RemoveEmptyEntries );
            int capped_length = build_order_chunks.Length - build_order_chunks.Length%3;
            //if( build_order_chunks.Length % 3 != 0 ) throw new Exception("BO Format is corrupt");

            m_Length = capped_length / 3;
            m_BuildBuckets = new string[m_Length];
            m_SecondBuckets = new int[m_Length];
            m_SupplyBuckets = new int[m_Length];
        
            SortedDictionary<char,int> dict = new SortedDictionary< char, int >();
            for( int i = 0 ; i < capped_length; ) {
                int index = i/3;
                string bo_chunk = build_order_chunks[ i ++ ];
                m_SupplyBuckets[index] = int.Parse( build_order_chunks[i ++] );
                m_SecondBuckets[index] = int.Parse( build_order_chunks[i ++] );


                for (int c_index = 0; c_index < bo_chunk.Length; c_index++) {
                    int num_instance;
                    char c = bo_chunk[ c_index ];
                    if( dict.TryGetValue( c, out num_instance ) == false ) {
                        dict[ c ] = 0;
                    }
                    dict[ c ]++;
                }
                StringBuilder sb = new StringBuilder();
                foreach (KeyValuePair<char, int> pair in dict) {
                    sb.Append( pair.Key ).Append( pair.Value );
                }
                m_BuildBuckets[index] = sb.ToString();//build_order_chunks[i ++];
            }
        }

        public string[] BuildBuckets { get { return m_BuildBuckets; } }
        public int[] SecondBuckets { get { return m_SecondBuckets; } }
        public int[] SupplyBuckets { get { return m_SupplyBuckets; } }
        public string Player { get { return m_Player; } }
        public string GameName { get { return m_GameName; } }

        public bool IsBuildEqual( BOCode rhs, int num_buckets ) {
            for (int i = 0; i < num_buckets; i++) if (m_BuildBuckets[i] != rhs.m_BuildBuckets[i]) return false;
            return true;
        }

        public String GetSubset( int num_buckets ) {
            return m_BuildBuckets[ num_buckets -1 ];
            //StringBuilder sb = new StringBuilder();
            //for (int i = 0; i < num_buckets; i++) sb.Append( m_BuildBuckets[ i ] );
            //return sb.ToString();
        }
    }
}
